﻿using Abp.Domain.Repositories;
using Camc.Quality.PadSocket;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using Camc.Quality.Bop;
using Abp.Auditing;
using Microsoft.AspNetCore.Http;

namespace Camc.Quality.FilesTransfer
{
    /// <summary>
    /// 文件传输，Tcp协议
    /// </summary>
    public class FilesTransferAppService : QualityAppServiceBase
    {
        private readonly IRepository<FileTransfer, Guid> _operationHeartBeat;
        private Socket clientSocket = null;
        private IHttpContextAccessor _clientInfoProvider;

        public FilesTransferAppService(
               IRepository<FileTransfer, Guid> operationHeartBeat,
               IHttpContextAccessor clientInfoProvider)
        {
            _operationHeartBeat = operationHeartBeat;
            _clientInfoProvider = clientInfoProvider;
        }
        public FilesTransferAppService(
               IRepository<FileTransfer, Guid> operationHeartBeat)
        {
            _operationHeartBeat = operationHeartBeat;
        }
        /// <summary>
        /// Pad列表的新增和更新
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task CreateOrUpdateHeartBeat(FileTransferDto input)
        {
            input.IPAddress = _clientInfoProvider.HttpContext.Connection.RemoteIpAddress.ToString();
            if (input.IPAddress.IndexOf("::ffff:") != -1)
            {
                input.IPAddress = input.IPAddress.Substring(7);
            }
            var heartBeat = ObjectMapper.Map<FileTransfer>(input);
            await _operationHeartBeat.InsertOrUpdateAsync(heartBeat);
        }
        /// <summary>
        /// 获取Pad列表
        /// </summary>
        /// <returns></returns>
        public async Task<List<FileTransferDto>> GetHeartBeatList()
        {
            //设定心跳包速率
            var dateNow = DateTime.Now.AddSeconds(-15);
            List<FileTransferDto> dtoList = new List<FileTransferDto>();
            var list = from temp in _operationHeartBeat.GetAll().Where(d => d.CreationTime >= dateNow)
                       select new FileTransferDto
                       {
                           IPAddress = temp.IPAddress,
                           Port = temp.Port,
                           PadID = temp.PadID,
                           PadName = temp.PadName
                       };

            return list.Distinct().ToList();
        }
        /// <summary>
        /// 测试接收广播
        /// </summary>
        //private void TestReceiveBroadcast(string ip, string port)
        //{
        //    Task task = new Task(() =>
        //    {
        //        Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); // 初始化一个Scoket协议



        /// <summary>
        /// 连接设备
        /// </summary>
        /// <param name="ip">Ip</param>
        /// <param name="port">端口</param>
        private void LinkDevice(IPAddress ip, int port)
        {
            clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            clientSocket.Connect(new IPEndPoint(ip, port));
            //addLog($"link device ip:{ip},port:{port}");
            clientSocket.Send(new TcpMessage(TcpMessageType.Message, "test").ToJsonByte());
        }
        /// <summary>
        /// 验证MD5加密
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public string VerifyMD5(string str)
        {
            return MD5Util.GetMD5Hash(str);
        }
        /// <summary>
        /// 通过Tcp往Pad端传输文件
        /// </summary>
        /// <param name="fileName">文件绝对路径</param>
        /// <param name="ip">Pad Ip地址</param>
        /// <param name="port">Pad 端口</param>
        /// <param name="nodeId">节点ID</param>
        /// <param name="padId">Pad唯一标志位</param>
        public void SendFile(string fileName, string ip, int port, Guid nodeId, string padId)
        {
            try
            {

                //建立Socket连接
                if (clientSocket == null || !clientSocket.Connected)
                {
                    IPAddress ipAddress = IPAddress.Parse(ip);
                    LinkDevice(ipAddress, port);
                }
                else
                {
                    clientSocket.Disconnect(false);
                    clientSocket.Close();
                    clientSocket.Dispose();
                    IPAddress ipAddress = IPAddress.Parse(ip);
                    LinkDevice(ipAddress, port);
                }
                if (clientSocket == null || !clientSocket.Connected)
                {
                    throw new Exception("连接已断开");
                }
                FileInfo fileInfo = new FileInfo(fileName);
                string pwMd5 = GetMD5HashFromFile(fileName);
                // string pwMd5 = MD5Util.GetMD5Hash("tianjingmes57");
                var msg = new TcpMessage(TcpMessageType.SendFile, "", fileInfo.Name, fileInfo.Length, pwMd5).ToJsonByte();
                clientSocket.Send(msg);
                clientSocket.SendFile(fileName);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// 获取文件Md5
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static string GetMD5HashFromFile(string fileName)
        {
            try
            {
                FileStream file = new FileStream(fileName, FileMode.Open);
                System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
                byte[] retVal = md5.ComputeHash(file);
                file.Close();

                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < retVal.Length; i++)
                {
                    sb.Append(retVal[i].ToString("x2"));
                }
                return sb.ToString();
            }
            catch (Exception ex)
            {
                throw new Exception("GetMD5HashFromFile() fail,error:" + ex.Message);
            }
        }
    }
}
